package cn.gwm.utils;


import org.apache.flink.api.java.tuple.Tuple2;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author Liu.Nanfang
 * @Date 2023/6/8 11:52
 * @Description 计算soe
 */
public class IntegralAreaSoe {
    /**
     * P03 梯度表
     * 表OCV 曲线忪告版软件必该表
     */
    private static final List<Tuple2<Integer, Double>> gradientTableArr = new ArrayList<>();

    static {

        gradientTableArr.add(new Tuple2<>(0, 3.3422));
        gradientTableArr.add(new Tuple2<>(5, 3.45977));
        gradientTableArr.add(new Tuple2<>(10, 3.5007));
        gradientTableArr.add(new Tuple2<>(15, 3.54191));
        gradientTableArr.add(new Tuple2<>(20, 3.57566));
        gradientTableArr.add(new Tuple2<>(25, 3.60924));
        gradientTableArr.add(new Tuple2<>(30, 3.63151));
        gradientTableArr.add(new Tuple2<>(35, 3.6494));
        gradientTableArr.add(new Tuple2<>(40, 3.66911));
        gradientTableArr.add(new Tuple2<>(45, 3.69462));
        gradientTableArr.add(new Tuple2<>(50, 3.73166));
        gradientTableArr.add(new Tuple2<>(55, 3.79058));
        gradientTableArr.add(new Tuple2<>(60, 3.85711));
        gradientTableArr.add(new Tuple2<>(65, 3.91676));
        gradientTableArr.add(new Tuple2<>(70, 3.97706));
        gradientTableArr.add(new Tuple2<>(75, 4.03756));
        gradientTableArr.add(new Tuple2<>(80, 4.09777));
        gradientTableArr.add(new Tuple2<>(85, 4.15333));
        gradientTableArr.add(new Tuple2<>(90, 4.20222));
        gradientTableArr.add(new Tuple2<>(95, 4.26001));
        gradientTableArr.add(new Tuple2<>(100, 4.36799));
    }

    public static void main(String[] args) {

        testComputeSoe(88.8);
        System.out.println("computeSoe:" + computeSoe(100.00));
        ;
    }

    public static void testComputeSoe(Double soc) {
        double x1 = 0.0;
        double x2 = 0.0;
        double value1 = 0.0;
        double value2 = 0.0;

        for (Tuple2<Integer, Double> item : gradientTableArr) {
            double currentX = item.f0;
            if (currentX <= soc) {
                x1 = currentX;
                value1 = item.f1;
            } else {
                x2 = currentX;
                value2 = item.f1;
                break;
            }

        }
        System.out.println("估计函数值： " + x1 + " " + value1 + " " + x2 + " " + value2 + " " + soc);

        // 获取 的估计函数值
        double interpolatedValue = interpolate(x1, value1, x2, value2, soc);
        System.out.println("估计函数值： " + interpolatedValue);
    }

    /**
     * 根据soc计算 soe 值
     *
     * @param soc
     * @return
     */
    public static BigDecimal computeSoe(Double soc) {
        System.out.println("soc: " + soc);
        if (soc == null || (soc != null && soc <= 0)) {
            return BigDecimal.ZERO;
        }

        // 计算从0到32.7之间的微积分面积
        double integralArea = calculateIntegralArea(gradientTableArr, 10, soc);
        double soe = 117 * integralArea * 1 * 88 / 1000;
        // 输出结果
        System.out.println("SOC： " + soc);
        System.out.println("微积分面积： " + integralArea);
        System.out.println("SOE： " + soe);

        return BigDecimal.valueOf(soe).setScale(2, BigDecimal.ROUND_HALF_UP);


    }

    /**
     * 线性插值计算估计函数值
     *
     * @param x1
     * @param y1
     * @param x2
     * @param y2
     * @param x
     * @return
     */
    private static double interpolate(double x1, double y1, double x2, double y2, double x) {
        return y1 + (y2 - y1) * (x - x1) / (x2 - x1);
    }

    /**
     * 计算从 start 到 end 之间的微积分面积
     *
     * @param gradientTable
     * @param start
     * @param end
     * @return
     */
    private static double calculateIntegralArea(List<Tuple2<Integer, Double>> gradientTable, int start, double end) {
        double sum = 0.0;
        for (int i = 0; i < gradientTable.size(); i++) {
            Tuple2<Integer, Double> entry = gradientTable.get(i);
            int currentK = entry.f0;
            double currentV = entry.f1;
            if (currentK < start) {
                continue;
            }
            if (currentK > end) {
                break;
            }
            int a = Math.max(start, currentK);
            double b = Math.min(end, currentK + 5);
            double interpolatedY;
            if (currentK >= 100) {
                interpolatedY = currentV;
            } else {
                interpolatedY = interpolate(currentK, currentV, currentK + 5, gradientTable.get(i + 1).f1, b);
            }
            double area = (Math.abs(b - a) * (currentV + interpolatedY)) / 2 / 100;
//            System.out.println("=====currentK: " + currentK + " currentV:" + currentV + " b: " + b + " a: " + a + " interpolatedY: " + interpolatedY + " area: " + area);
            sum += area;

        }
        return sum;
    }
}
